package com.canaan.business.controller.pc.bill;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Pair;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.canaan.business.common.enums.inOutStock.BillBindOperationEnum;
import com.canaan.business.common.enums.inOutStock.ErpBillTypeEnum;
import com.canaan.business.common.enums.inOutStock.InOrderStatusEnum;
import com.canaan.business.domain.bill.*;
import com.canaan.business.domain.vo.*;
import com.canaan.business.service.bill.*;
import com.canaan.common.annotation.Log;
import com.canaan.common.core.controller.BaseController;
import com.canaan.common.core.domain.AjaxResult;
import com.canaan.common.core.page.TableDataInfo;
import com.canaan.common.encrypt.PushEdiService;
import com.canaan.common.enums.BusinessType;
import com.canaan.common.exception.ServiceException;
import com.canaan.common.utils.DateUtils;
import com.canaan.common.utils.StringUtils;
import com.canaan.common.utils.poi.ExcelUtil;
import com.canaan.system.service.ISysConfigService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 调拔入库单Controller
 *
 * @author ruoyi
 * @date 2023-02-01
 */
@Api(tags = "调拔入库单")
@RestController
@RequestMapping("/bill/adjustIn")
public class AdjustInBillController extends BaseController {
    @Resource
    private IAdjustInBillService adjustInBillService;
    @Resource
    private IAdjustInBillDetailService adjustInBillDetailService;
    @Resource
    private IBillDetailRecordService billDetailRecordService;
    @Resource
    private ITrayService trayService;
    @Resource
    private ITrayDetailService trayDetailService;
    @Resource
    private ISysConfigService sysConfigService;


    /**
     * 查询调拔入库单列表
     */
    @ApiOperation(value = "查询调拔入库单列表")
    @GetMapping("/list")
    public TableDataInfo list(AdjustInBill adjustInBill) {
        startPage();
        List<AdjustInBill> list = adjustInBillService.selectAdjustInBillListPageDatas(adjustInBill);
        return getDataTable(list);
    }

    /**
     * 导出调拔入库单列表
     */
    @ApiOperation(value = "导出调拔入库单列表")
    @Log(title = "调拔入库单", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, AdjustInBill adjustInBill) {
        List<AdjustInBillExportVo> list = adjustInBillService.exportList(adjustInBill);
        ExcelUtil<AdjustInBillExportVo> util = new ExcelUtil<>(AdjustInBillExportVo.class);
        util.exportExcel(response, list, "调拔入库单数据");
    }
    /**
     * 导出调拔入库单清单列表
     */
    @ApiOperation(value = "导出调拔入库单清单列表")
    @Log(title = "调拔入库单清单", businessType = BusinessType.EXPORT)
    @PostMapping("/exportCheck")
    public void exportCheck(HttpServletResponse response, AdjustInBill adjustInBill) {
        List<AdjustInBillExportCheckVo> list = adjustInBillService.exportCheckList(adjustInBill);
        ExcelUtil<AdjustInBillExportCheckVo> util = new ExcelUtil<>(AdjustInBillExportCheckVo.class);
        util.exportExcel(response, list, "调拔入库单清单数据");
    }

    /**
     * 获取调拔入库单详细信息
     */
    @ApiOperation(value = "获取调拔入库单详细信息")
    @GetMapping(value = "/{id}")
    public AjaxResult getInfo(@PathVariable("id") Long id) {
        return success(adjustInBillService.selectAdjustInBillById(id));
    }

    /**
     * 新增调拔入库单
     */
    @ApiOperation(value = "新增调拔入库单")
    @Log(title = "调拔入库单", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody AdjustInBill adjustInBill) {
        return toAjax(adjustInBillService.insertAdjustInBill(adjustInBill));
    }

    /**
     * 修改调拔入库单
     */
    @ApiOperation(value = "修改调拔入库单")
    @Log(title = "调拔入库单", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody AdjustInBill adjustInBill) {
        return toAjax(adjustInBillService.updateAdjustInBill(adjustInBill));
    }

    /**
     * 删除调拔入库单
     */
    @ApiOperation(value = "删除调拔入库单")
    @Log(title = "调拔入库单", businessType = BusinessType.DELETE)
    @DeleteMapping("/{ids}")
    public AjaxResult remove(@PathVariable Long[] ids) {
        return toAjax(adjustInBillService.deleteAdjustInBillByIds(ids));
    }

    @ApiOperation(value = "完成收货")
    @Log(title = "完成收货", businessType = BusinessType.UPDATE)
    @PostMapping("/complete")
    public AjaxResult complete(@RequestBody ReceiveProductBill receiveProductBill) {
        AdjustInBill bill = adjustInBillService.selectAdjustInBillByNo(receiveProductBill.getNo());
        if (bill == null) {
            return error("调拨入库单" + receiveProductBill.getNo() + "不存在");
        }
        if (StrUtil.equals(bill.getShortMatch(), "0") && Long.compare(bill.getTotalQty(), bill.getCheckTotalQty()) > 0) {
            //不支持短收
            return error("调拨入库单" + receiveProductBill.getNo() + "不支持短收");
        }
        bill.setStatus(InOrderStatusEnum.ACCOMPLISH.getCode());
        bill.setCompleteTime(DateUtils.getNowDate());
        adjustInBillService.postInStockCallback(bill.getNo(), bill.getStockStatus());
        int result = adjustInBillService.updateAdjustInBill(bill);
        return toAjax(result);
    }

    /**
     * 订单确认
     */
    @ApiOperation(value = "订单确认")
    @Log(title = "订单确认", businessType = BusinessType.UPDATE)
    @PutMapping("/confirm")
    public AjaxResult confirm(@RequestBody List<Long> ids) {
        if (ids == null || ids.isEmpty()) {
            throw new ServiceException("缺少必要参数");
        }
        return toAjax(adjustInBillService.confirm(ids));
    }


    /**
     * 调拔入库导入模板
     */
    @ApiOperation(value = "调拔入库导入模板")
    @PostMapping("/importTemplate")
    public void importTemplate(HttpServletResponse response) {
        ExcelUtil<AdjustInBillExportVo> util = new ExcelUtil<>(AdjustInBillExportVo.class);
        util.importTemplateExcel(response, "调拔入库导入模板");
    }

    /**
     * 导入调拔入库
     */
    @ApiOperation(value = "导入调拔入库")
    @PostMapping("/importExcel")
    @Log(title = "导入调拔入库", businessType = BusinessType.IMPORT)
    public AjaxResult importExcel(MultipartFile file) {
        List<AdjustInBillExportVo> list;
        try {
            //读取excel文件数据
            ExcelUtil<AdjustInBillExportVo> util = new ExcelUtil<>(AdjustInBillExportVo.class);
            list = util.importExcel(file.getInputStream());
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServiceException("导入文件解析失败");
        }
        //初步校验数据
        if (CollectionUtils.isEmpty(list)) {
            throw new ServiceException("文件缺少数据");
        }

        //深入校验数据和保存数据
        List<String> errorList = adjustInBillService.importExcel(list);
        if (!errorList.isEmpty()) {
            StringBuilder failureMsg = new StringBuilder();
            failureMsg.append("很抱歉，导入失败！共 ").append(errorList.size()).append(" 条数据格式不正确，错误如下：");
            for (int i = 0; i < errorList.size(); i++) {
                failureMsg.append("<br/>").append(i + 1).append("、").append(errorList.get(i));
            }
            return error(failureMsg.toString());
        }
        return success("导入成功");
    }

    /**
     * 订单取消
     */
    @ApiOperation(value = "订单取消")
    @Log(title = "订单取消", businessType = BusinessType.UPDATE)
    @PutMapping("/cancel")
    public AjaxResult cancel(@RequestBody List<Long> ids) {
        return success(adjustInBillService.cancel(ids));
    }

    /**
     * 订单确认取消
     */
    @ApiOperation(value = "订单确认取消")
    @Log(title = "订单取消", businessType = BusinessType.UPDATE)
    @PutMapping("/confirmCancel")
    public AjaxResult cancel(@RequestBody AdjustInBill adjustInBill) {
        if(adjustInBill == null || adjustInBill.getId() == null){
            throw new ServiceException("缺少必要参数");
        }
        return success(adjustInBillService.confirmCancel(adjustInBill));
    }
    /**
     * 收货
     */
    @ApiOperation(value = "收货")
    @Log(title = "收货", businessType = BusinessType.UPDATE)
    @PostMapping("/addDetail")
    @Transactional
    public AjaxResult addDetail(@RequestBody AdjustInDetailVo adjustInDetailVo){
        if (StringUtils.isEmpty(adjustInDetailVo.getTrayNo())) {
            return error("托盘号不能为空");
        } else if (!StringUtils.startsWith(adjustInDetailVo.getTrayNo(), "T")) {
            return error("托盘号不正确");
        }
        if (adjustInDetailVo.getProductDate() == null) {
            return error("生产日期不能为空");
        }
        int result = addAdjustInBillDetail(adjustInDetailVo) ? 1 : 0;
        return toAjax(result);
    }

    /**
     * 添加收货明细
     * @param adjustInDetailVo 收货明细
     * @return
     */
    private boolean addAdjustInBillDetail(AdjustInDetailVo adjustInDetailVo){
        //更新明细数量
        AdjustInBillDetail query=new AdjustInBillDetail();
        query.setBillNo(adjustInDetailVo.getBillNo());
        query.setProductNo(adjustInDetailVo.getProductNo());
        query.setDelFlag("0");

        TrayDetail trDetail = new TrayDetail();
        trDetail.setTrayNo(adjustInDetailVo.getTrayNo());
        List<TrayDetail> trayDetails =  trayDetailService.selectTrayDetailList(trDetail);
        if (CollectionUtil.isNotEmpty(trayDetails)) {
            //一个托盘只能放一种物料和一个批次
            throw new RuntimeException("托盘" + adjustInDetailVo.getTrayNo() + "已经存在物料" + trayDetails.get(0).getProductNo());
        }

        AdjustInBill adjustInBill=adjustInBillService.selectAdjustInBillByNo(adjustInDetailVo.getBillNo());
        if (adjustInBill==null){
            throw new RuntimeException("调拨入库单"+adjustInDetailVo.getBillNo()+"不存在");
        }
        if(adjustInBill.getCheckTotalQty()+adjustInDetailVo.getQty()>adjustInBill.getTotalQty()){
            throw new RuntimeException("调拨入库单"+adjustInDetailVo.getBillNo()+"收货总数超过"+adjustInBill.getTotalQty());
        }
        adjustInBill.setCheckTotalQty(adjustInBill.getCheckTotalQty()+adjustInDetailVo.getQty());
        adjustInBill.setStatus(InOrderStatusEnum.PICKING.getCode());
        adjustInBillService.updateAdjustInBill(adjustInBill);

        List<AdjustInBillDetail> adjustInBillDetails=adjustInBillDetailService.selectAdjustInBillDetailList(query);
        if(adjustInBillDetails==null||adjustInBillDetails.size()==0){
            throw new RuntimeException(adjustInDetailVo.getBillNo()+"不存在物料"+adjustInDetailVo.getProductNo()+"明细");
        }
        AdjustInBillDetail adjustInBillDetail=adjustInBillDetails.get(0);
        if(adjustInBillDetail.getReceivedQty()+adjustInDetailVo.getQty()>adjustInBillDetail.getQty()){
            throw new RuntimeException(adjustInDetailVo.getBillNo()+"不存在物料"+adjustInDetailVo.getProductNo()+"明细超出数量"+adjustInBillDetail.getQty());
        }
        //增加单据明细
        BillDetailRecord billDetailRecord=new BillDetailRecord();
        billDetailRecord.setBillNo(adjustInDetailVo.getBillNo());
        billDetailRecord.setTrayNo(adjustInDetailVo.getTrayNo());
        billDetailRecord.setBillType(ErpBillTypeEnum.ADJUST_IN.getCode());
        billDetailRecord.setProductNo(adjustInDetailVo.getProductNo());
        billDetailRecord.setProductName(adjustInDetailVo.getProductName());
        billDetailRecord.setBatchNo(adjustInDetailVo.getBatchNo());
        billDetailRecord.setQty(adjustInDetailVo.getQty());
        billDetailRecord.setProductUnit(adjustInDetailVo.getProductUnit());
        billDetailRecord.setOperation(BillBindOperationEnum.ADJUST_IN.getMessage());
        billDetailRecord.setStockStatus(adjustInBill.getStockStatus());
        billDetailRecord.setProductionDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD,adjustInDetailVo.getProductDate()));
        billDetailRecord.setExpiryDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD,adjustInDetailVo.getValidDate()));
        billDetailRecordService.insertBillDetailRecord(billDetailRecord);
        //修改对应的明细表批次号,返回给EDI时需要用到
        adjustInBillDetail.setBatchNo(adjustInDetailVo.getBatchNo());
        adjustInBillDetail.setReceivedQty(adjustInBillDetail.getReceivedQty()+adjustInDetailVo.getQty());
        adjustInBillDetailService.updateAdjustInBillDetail(adjustInBillDetail);
        //增加托盘
        Tray tray=trayService.selectTrayByTrayNo(adjustInDetailVo.getTrayNo());
        if(tray==null){
            tray=new Tray();
            tray.setErpInBillNo(adjustInBill.getNo());
            tray.setStockStatus(adjustInBill.getStockStatus());
            tray.setTrayNo(adjustInDetailVo.getTrayNo());
            tray.setOwner(adjustInBill.getOwner());
            tray.setStockCode(adjustInBill.getStockCode());
            trayService.insertTray(tray);
        }
        else{
            tray.setErpInBillNo(adjustInBill.getNo());
            tray.setStockStatus(adjustInBill.getStockStatus());
            tray.setErpOutBillNo("");
            tray.setSplitBillNo("");
            tray.setOutBillNo("");
            tray.setInBillNo("");
            tray.setOwner(adjustInBill.getOwner());
            tray.setStockCode(adjustInBill.getStockCode());
            trayService.updateTray(tray);
        }
        //增加托盘明细
        TrayDetail trayDetailQuery=new TrayDetail();
        trayDetailQuery.setTrayNo(adjustInDetailVo.getTrayNo());
        trayDetailQuery.setProductNo(adjustInDetailVo.getProductNo());
        trayDetailQuery.setBatchNo(adjustInDetailVo.getBatchNo());
        trayDetailQuery.setDelFlag("0");
        List<TrayDetail> trayResults=trayDetailService.selectTrayDetailList(trayDetailQuery);
        if(trayResults!=null&&trayResults.size()!=0){
            throw new RuntimeException("托盘"+adjustInDetailVo.getTrayNo()+"已经存在物料"+adjustInDetailVo.getProductNo()+"明细");
        }
        TrayDetail trayDetail =new TrayDetail();
        trayDetail.setTrayNo(adjustInDetailVo.getTrayNo());
        trayDetail.setProductName(adjustInDetailVo.getProductName());
        trayDetail.setProductNo(adjustInDetailVo.getProductNo());
        trayDetail.setProductUnit(adjustInDetailVo.getProductUnit());
        trayDetail.setBatchNo(adjustInDetailVo.getBatchNo());
        trayDetail.setStockStatus(adjustInBill.getStockStatus());
        trayDetail.setQty(adjustInDetailVo.getQty());
        trayDetail.setProductionDate(adjustInDetailVo.getProductDate());
        if(adjustInDetailVo.getValidDate()!=null&&adjustInDetailVo.getProductDate()!=null) {
            trayDetail.setValidDateNum(DateUtils.differentDaysByMillisecond(adjustInDetailVo.getValidDate(), adjustInDetailVo.getProductDate()));
        }
        trayDetailService.insertTrayDetail(trayDetail);
        return  true;
    }
    /**
     * 确定
     */
    @ApiOperation(value = "删除明细")
    @Log(title = "删除明细", businessType = BusinessType.UPDATE)
    @PostMapping("/deleteDetail")
    public AjaxResult deleteDetail(@RequestBody ReceiveProductDetailVo detailVo){
        int result=deleteReceiveProductDetail(detailVo)?1:0;
        return toAjax(result);
    }

    /**
     * 删除明细
     * @param detailVo
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteReceiveProductDetail(ReceiveProductDetailVo detailVo){
        //更新明细数量
        AdjustInBillDetail query=new AdjustInBillDetail();
        query.setBillNo(detailVo.getBillNo());
        query.setProductNo(detailVo.getProductNo());
        query.setDelFlag("0");

        AdjustInBill adjustInBill =adjustInBillService.selectAdjustInBillByNo(detailVo.getBillNo());
        if (adjustInBill ==null){
            throw new RuntimeException("调拨入库单"+detailVo.getBillNo()+"不存在");
        }
        if(adjustInBill.getCheckTotalQty()-detailVo.getQty()<0){
            adjustInBill.setCheckTotalQty(0l);
        }
        else {
            adjustInBill.setCheckTotalQty(adjustInBill.getCheckTotalQty() - detailVo.getQty());
        }
        adjustInBillService.updateAdjustInBill(adjustInBill);

        List<AdjustInBillDetail> adjustInBillDetails =adjustInBillDetailService.selectAdjustInBillDetailList(query);
        if(adjustInBillDetails ==null|| adjustInBillDetails.size()==0){
            throw new RuntimeException("调拨入库单"+detailVo.getBillNo()+"不存在物料"+detailVo.getProductNo()+"明细");
        }
        AdjustInBillDetail receiveProductBillDetail= adjustInBillDetails.get(0);
        if(receiveProductBillDetail.getReceivedQty()-detailVo.getQty()<0){
            receiveProductBillDetail.setReceivedQty(0l);
        }
        else{
            receiveProductBillDetail.setReceivedQty(receiveProductBillDetail.getReceivedQty()-detailVo.getQty());
        }
        adjustInBillDetailService.updateAdjustInBillDetail(receiveProductBillDetail);
        //增加单据明细
        BillDetailRecord billDetailQuery=new BillDetailRecord();
        billDetailQuery.setBatchNo(detailVo.getBatchNo());
        billDetailQuery.setBillNo(detailVo.getBillNo());
        billDetailQuery.setTrayNo(detailVo.getTrayNo());
        billDetailQuery.setProductNo(detailVo.getProductNo());
        billDetailQuery.setDelFlag("0");
        List<BillDetailRecord> billDetailRecords=billDetailRecordService.selectBillDetailRecordList(billDetailQuery);
        if(billDetailRecords==null||billDetailRecords.size()==0){
            throw new RuntimeException(detailVo.getBillNo()+"单据明细中不存在托盘"+detailVo.getTrayNo()+"物料"+detailVo.getProductNo());
        }
        BillDetailRecord record=billDetailRecords.get(0);
        billDetailRecordService.deleteBillDetailRecordById(record.getId());
        //删除托盘明细
        TrayDetail trayDetailQuery =new TrayDetail();
        trayDetailQuery.setTrayNo(detailVo.getTrayNo());
        trayDetailQuery.setProductNo(detailVo.getProductNo());
        trayDetailQuery.setBatchNo(detailVo.getBatchNo());
        trayDetailQuery.setDelFlag("0");
        List<TrayDetail> trayDetails=trayDetailService.selectTrayDetailList(trayDetailQuery);
        if(trayDetails==null||trayDetails.size()==0){
            throw new RuntimeException("托盘"+detailVo.getTrayNo()+"明细中不存在物料"+detailVo.getProductNo());
        }
        TrayDetail trayDetail=trayDetails.get(0);
        trayDetailService.deleteTrayDetailById(trayDetail.getId());
        return  true;
    }


    /**
     * 调拨入库单打印
     */
    @ApiOperation(value = "调拨入库单打印")
    @Log(title = "调拨入库单打印", businessType = BusinessType.EXPORT)
    @GetMapping("/selectAdjustInBillForPrint")
    public AjaxResult selectAdjustInBillForPrint(@RequestParam("no") String no) {
        return success(adjustInBillService.selectAdjustInBillForPrint(no));
    }
}
